<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="keywords" content="好好学习">
    <meta name="description" content="这是一个学习的第一课">
    <title>JS学习</title>
    <style>
        body,p,h1,h2,h3,h4,h5,h6,ul{margin: 0;padding: 0;}
        body{font:12px"宋体","Arial Narrow",HELVETICA;background:#fff;-webkit-text-size-adjust:100%;}
        li{list-style: none;}
        a{text-decoration: none;}
        img{border: 0;vertical-align: middle;}
        #wrap{
            position: relative;
            margin: 0 auto;
            width: 512px;
            height: 768px;
            overflow: hidden;
            background: url("./images/bg_1.jpg");
            user-select: none;
        }
        #wrap div{
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
        }
        #wrap .homeScreen h2{
            margin: 150px auto 50px;
            font-size: 50px;
            color: #fff;
            font-family: "黑体";
            text-align: center;
        }
        #wrap .homeScreen p{
            margin: 20px auto;
            width: 50%;
            height: 40px;
            font-size: 20px;
            color: #000;
            line-height: 40px;
            font-family: "黑体";
            text-align: center;
            background: #ccc;
            cursor: pointer;
        }
        #wrap .homeScreen p:hover{
            color: #fff;
            background: #000;
        }
        .game span{
            position: absolute;
            top: 5px;
            left: 10px;
            font-size: 30px;
            color: #fff;
        }
        .over{
            box-sizing: border-box;
            padding-top: 150px;
        }
        .over p{
            margin-top: 30px;
            font-family: "黑体";
            text-align: center;
            color: #fff;
            font-size: 30px;
        }
        .over .restartBtn{
            margin: 100px auto 0;
            width: 200px;
            height: 50px;
            line-height: 50px;
            background: #ccc;
            color: #000;
            cursor: pointer;
        }
        .over .restartBtn:hover{
            background: #000;
            color: #fff;
        }
    </style>
</head>
<body>
    <div id="wrap">
        <div class="homeScreen">
            <h2>飞机大战</h2>
            <p>简单</p>
            <p>中等</p>
            <p>困难</p>
        </div>
        <div class="game"><span>0</span></div>
        <div class="over">
            <p>游戏结束</p>
            <p>你的得分</p>
            <p class="finalScore">0</p>
            <p class="restartBtn">重新开始</p>

        </div>
    </div>
    <script>
        
        let homeScreen = document.querySelector(".homeScreen"),
            game = document.querySelector(".game"),
            over = document.querySelector(".over"),
            level = document.querySelectorAll(".homeScreen p"),
            gameScore = document.querySelector(".game span"),
            finalScore = document.querySelector(".finalScore"),
            restartBtn = document.querySelector(".restartBtn")
        ;
        //游戏系数
        let enemyRate = 0,
            enemySpeed = 0,
            bulletRate = 0,
            bulletSpeed = 0;
        

        //构造基础
        class Sprite{
            constructor(imgSrc, width, height, x = 0, y = 0) {
                this.img = new Image();
                this.img.src = imgSrc;
                this.img.width = width;
                this.img.height = height;
                this.img.style.position = "absolute";
                this.img.style.left = x + "px";
                this.img.style.top = y + "px";
            }
            //在界面中显示DOM
            show() {
                game.appendChild(this.img);
            }
            //界面中移除DOM
            remove() {
                game.removeChild(this.img);
            }
        }
        //游戏基础数据
        class gameData{
            reset() {
                this.frame = 0;
                this.score = 0;
                this.bullets = [];
                this.enemys = [];
                this.gameOver = false;
            }
            //数据中清除敌军
            removeEnemy(enemy) {
                let temp = this.enemys.indexOf(enemy);
                this.enemys.splice(temp, 1);
            }
            //数据中清除子弹
            removeBullet(bullet) {
                let temp = this.bullets.indexOf(bullet);
                this.bullets.splice(temp, 1);
            }
        }
        //定义子弹
        class Bullet extends Sprite{
            constructor(levelDate) {
                super("./images/fire.png", 6, 12);
            }
            //初始化子弹位置，并在界面中显示DOM,添加到gamedata.bullets  Arr
            init(x, y) {
                this.img.style.left = x + "px";
                this.img.style.top = y + "px";
                this.show();
                gamedata.bullets.push(this);
            }
            //更新子弹位置，超出界面后，移除
            update() {
                this.img.style.top = this.img.offsetTop - bulletSpeed + "px";
                if(this.img.offsetTop < -this.img.height){
                    this.remove();
                    gamedata.removeBullet(this);
                } 
            }
        }
        //定义飞机
        class Plane extends Sprite{
            constructor(ev) {
                let _x = ev.pageX - wrap.offsetLeft - 25;
                let _y = ev.pageY - wrap.offsetTop - 25;
                super("./images/plane_1.png", 50, 50, _x, _y);
                this.show();
                this.initEvent();
            }
            //飞机坐标传参XY
            planeMove(x, y) {
                x = Math.min(x, wrap.clientWidth - this.img.width/2);
                x = Math.max(x, -this.img.width/2);
                y = Math.min(y, wrap.clientHeight - this.img.height/2);
                y = Math.max(y, 0);
                this.img.style.left = x + "px";
                this.img.style.top = y + "px";
            }
            //监听鼠标移动
            initEvent() {
                if(this) {
                    document.addEventListener("mousemove", (function(ev) {
                        let x = ev.clientX - wrap.offsetLeft - this.img.width/2;
                        let y = ev.clientY - wrap.offsetTop - this.img.height/2;
                        this.planeMove(x, y);
                    }).bind(this))
                }
                
            }
            //飞机射击
            shoot() {
                let bullet = new Bullet();
                bullet.init(this.img.offsetLeft + this.img.width/2 - bullet.img.width/2, this.img.offsetTop - 10);
            }
        } 
        //返回一个随机数
        function rdn(start, end) {
            return Math.floor(Math.random()*(end - start) + start)
        }
        //定义敌军
        class Enemy extends Sprite{
            constructor() {
                super("./images/enemy_small.png", 50, 40);
                this.init();
            }
            //初始化敌军飞机位置，界面中显示该DOM，添加到数组
            init() {
                this.img.style.left = rdn(0, wrap.offsetWidth) - this.img.width/2 + "px";
                this.img.style.top = -this.img.height + "px";
                this.rdnSpeed = rdn(0, 3);
                this.show();
                gamedata.enemys.push(this);
            }
            update() {
                this.img.style.top = this.img.offsetTop + enemySpeed + this.rdnSpeed + "px";
                if(this.img.offsetTop > wrap.offsetHeight){
                    this.remove();
                    gamedata.removeEnemy(this);
                } 
            }
            boom() {
                gamedata.removeEnemy(this);
                this.img.src = "./images/boom_small.png";
                this.img.style.transition = ".5s";
                this.img.style.opacity = "0";
                this.img.addEventListener("transitionend", function() {
                    this.remove();
                }.bind(this))
            }
        }
        class Play{
            constructor(ev) {
                this.gameInitialization();
                this.start(ev);
            }
            //游戏界面切换
            gameInitialization() {
                homeScreen.style.display = "none";
                game.style.display = "block";
                over.style.display = "none";
            }
            //开始游戏
            start(ev) {
                gamedata.reset();
                this.plane = new Plane(ev);
                this.bindLoop = this.loop.bind(this);
                this.loop();
            }
            //游戏结束，弹出清算界面，移除所有DOM，
            gameOver() {
                game.style.display = "none";
                over.style.display = "block";
                this.plane.remove();
                gamedata.enemys.concat(gamedata.bullets).forEach(ele=>{
                        ele.remove();
                }) 
                finalScore.innerHTML = gamedata.score;

            }
            //检车是否碰撞
            isImpact(ememy, ele) {
                return ((ele.img.offsetLeft + ele.img.offsetWidth) >= ememy.img.offsetLeft && ele.img.offsetLeft <= (ememy.img.offsetLeft + ememy.img.offsetWidth)
                    && ele.img.offsetTop <= (ememy.img.offsetTop + ememy.img.offsetHeight) && (ele.img.offsetTop + ele.img.offsetHeight) >= ememy.img.offsetTop
                ) 
            }
            //全局检查碰撞
            collisionDetection() {
                gamedata.enemys.forEach(function(ele) {
                    //敌军和子弹
                    for(let i = 0; i < gamedata.bullets.length; i++) {
                        if(this.isImpact(ele, gamedata.bullets[i])) {
                            gamedata.score += 10;
                            gamedata.bullets[i].remove();
                            gamedata.removeBullet(gamedata.bullets[i]);
                            ele.boom();
                            break;
                        }
                    }
                    //敌军和飞机
                    if(this.isImpact(ele, this.plane)) {
                        gamedata.gameOver = true;
                    }
                }.bind(this))
            }
            //每一帧更新内容
            update() {
                //移动
                gamedata.enemys.concat(gamedata.bullets).forEach(ele=>{
                    ele.update();
                })
                //检测碰撞
                this.collisionDetection();
                //更新分数
                gameScore.innerHTML = gamedata.score;
                //生成敌军
                if(gamedata.frame % enemyRate === 0) {
                    let enemy = new Enemy();
                }
                //发射子弹
                if(gamedata.frame % bulletRate === 0) {
                    this.plane.shoot();
                }
            }
            //循环
            loop() {
                if(!gamedata.gameOver) {
                    gamedata.frame++;
                    this.update();
                    requestAnimationFrame(this.bindLoop);
                }else {
                    this.gameOver();
                }
                
            }
        }
        class UI{
            constructor() {
                game.style.display = "none";
                over.style.display = "none";
                this.select();
                this.restart();
            }
            //点击按钮选择难度  开始游戏
            select() {
                [...level].forEach((ele, index)=>{
                    ele.onclick = function(ev) {
                        enemyRate = [20,15,10][index];
                        enemySpeed = [4,5,6][index];
                        bulletRate = [10,15,25][index];
                        bulletSpeed = [10,6,4][index];
                        this.play = new Play(ev);
                    }
                })
            }
            //点击重新开始
            restart() {
                restartBtn.onclick = function() {
                    over.style.display = "none";
                    homeScreen.style.display = "block";
                }
            }

        }
        let ui = new UI();
        let gamedata = new gameData();
    </script>
</body>
</html>